#include "Zuma.h"
#include "ZumaThread.h"
#include "BallGenerator.h"
#include "NoIntersectException.h"
#include "DeadFrogException.h"
#include "GameOverException.h"
#include "LevelEndedException.h"

using namespace std;


int finishingDrawing = 0;
int done = 0;
int fireing = 0;
int drawThreadDelay = 60;
int moveThreadDelay = 60;
int minDelayBonusTime = 6000;
int maxDelayBonusTime = 16000;

	
int stageDraw(void *data);
int moveElements(void *data);
int generateBalls(void *data);
int generateRandomBonus(void *data);
int getRandomDelay();
bool mustRestartStage = false;
bool isStageOver = false;
bool isGameOver = false;

bool keyHasBeenProcessed = true;

#define PI 3.14159265


Zuma::Zuma(void){
	this->logger = LogFactory::getInstance()->getLog();
	drawThreadDelay = 1000/General::getInstance()->getFramesPerSecond();
}

Zuma::~Zuma(void){
	if(this->stages != NULL){
		this->stages->clear();
		delete this->stages;
	}
	delete DaoFactory::getInstance();
	delete General::getInstance();
}

int Zuma::startStage( Stage * stage ){
		
	this->stage = stage;
	this->stage->initialize();
	stage->reversePowerOff();
	stage->accumulatedTime=0;
	stage->actualPercentage = 1;
	stage->ballsCounter=0;
	stage->points=0;
	stage->counter=0;
						
	BallGenerator::getInstance()->setStage(this->stage);
	this->stage->getFrog()->setInitialized(false);
	if(General::getInstance()->vidas!=-1){
		stage->getVida()->setCantidad(General::getInstance()->vidas);
	}else{
		General::getInstance()->vidas=stage->getVida()->getCantidad();
	}
	stage->getScore()->setScore(General::getInstance()->score);

	keyHasBeenProcessed = true;
	done = 0;
	fireing =0;		
	finishingDrawing=0;	
	ZumaThread *drawThread = new ZumaThread(stageDraw,this->stage);
	drawThread->runForest();
	ZumaThread* bonusGenerator = new ZumaThread(generateRandomBonus,stage);
	bonusGenerator->runForest();
	this->stage->setHasActiveBall(false);
	SDL_Event  evt;
	while(done == 0){
		while(SDL_PollEvent(&evt)){
			if(mustRestartStage) {
				stage->resetStage();
				mustRestartStage = false;
				drawThread->runForest();
			}
			if(isGameOver) {
				done = 1;
				TTF_Quit();
				return 1;
			}
			if(evt.type == SDL_KEYDOWN){
				while(finishingDrawing){}
				printf("Paso por la letra");
				switch(evt.key.keysym.sym){
					case SDLK_LEFT:	
						keyHasBeenProcessed = false;
						stage->modifyVelocityPercentage(-1);
						keyHasBeenProcessed = true;
						break;
					case SDLK_RIGHT:
						keyHasBeenProcessed = false;
						if(stage->isReverseOn){
							stage->reversePowerOff();
						}else{
							stage->reversePowerOn();
						}
						keyHasBeenProcessed = true;
						break;
					case SDLK_UP:
						stage->setLaserOn();
						break;
					default:
						break;
				}
			}
			if(evt.type == SDL_QUIT){
				done = 1;
				while(finishingDrawing){
					SDL_Delay(100);
				}
				TTF_Quit();
				return 1;
			}
			
			if(evt.type == SDL_MOUSEBUTTONDOWN){
				if (SDL_GetMouseState(NULL, NULL)& SDL_BUTTON(1)){
					if(!this->stage->getHasActiveBall()){
						while(finishingDrawing){}
						fireing = 1;
						Position *position = new Position(evt.button.x,evt.button.y);
						//Ball* ball = stage->getFrog()->fireBall(position,this->stage->getInitialVelocityModule()*2);
						Ball* ball = stage->getFrog()->fireBall(position,420);
						this->stage->refrehBallsView(stage->getFrog()->getMainBall(),stage->getFrog()->getSecondaryBall());
						this->stage->setActiveBall(ball);
						this->stage->setHasActiveBall(true);
						delete position;
						list<DrawableElement*>::iterator iterObstacles;
						
						for(iterObstacles = stage->getObstacles()->begin();iterObstacles != stage->getObstacles()->end();iterObstacles++) {
							DrawableElement * obstacle = *iterObstacles;
							try {
								obstacle->evaluateCollision(ball);
							}catch(NoIntersectException e) {
								printf("No intersecta %s",obstacle->getType());
							}
						}

						stage->getRail()->checkBallAndRailIntersection(ball);
						stage->setActiveBall(ball);
						stage->setHasActiveBall(true);
						fireing = 0;		
					}  
				}	
			
				if(SDL_GetMouseState(NULL, NULL)&SDL_BUTTON(3) ){
					stage->getFrog()->swapBalls();
					stage->refrehBallsView(this->stage->getFrog()->getMainBall(),this->stage->getFrog()->getSecondaryBall());
				}	
			
			}
			
			if(evt.type == SDL_MOUSEMOTION) {	
				
				while(finishingDrawing){
					SDL_Delay(50);
				}
				
				Frog* frog = stage->getFrog();
				int mx = evt.motion.x;
				int my = evt.motion.y;
				int x = mx - frog->getPosition()->getPixelX();
				int y = frog->getPosition()->getPixelY() - my;
				int angle = int(atan2(double(y), double(x)) * 180 / PI);
				stage->setMousePosition(mx,my);
				if(angle < 0) {
					angle = 360 + angle;
				}
				frog->setAngle(angle);
			}
		}
	}
	return 0;
}

int stageDraw(void *data){

	Stage *stage = (Stage* )data;
	try {
		while (done == 0 ){
			while(fireing){};
			while(!keyHasBeenProcessed){}
			try {
				finishingDrawing = 1;
				stage->draw();
				finishingDrawing = 0;
				General::getInstance()->score= stage->getScore()->getScore();
			}catch(DeadFrogException e) {
				finishingDrawing = 1;
				(*stage->getVida())--;
				stage->getVida()->draw();
				mustRestartStage = true;
				finishingDrawing = 0;
				return 0;
			}catch(LevelEndedException lee){
				done = 1;
				finishingDrawing = 0;
				General::getInstance()->score= stage->getScore()->getScore();
				return 0;
			}
			SDL_Delay(drawThreadDelay);
		}
	}catch(GameOverException e) {
		stage->gameOver();
		SDL_Delay(1000);
		isGameOver = true;
		finishingDrawing = 0;
		return 1;
	}
	finishingDrawing = 0;
	return 0;
}

list<Stage *> * Zuma::getStages( void ){
	return this->stages;
}

void Zuma::setStages( list<Stage *> * stages ){
	this->stages = stages;
}

int generateRandomBonus(void *data){

	Stage *stage = (Stage* )data;
	
	int bonusSize = stage->getBonusBalls()->size();
	
	list<Bonuz*>::iterator theIterator;
	list<Bonuz*> * bonusList = stage->getBonusBalls();
	
	while (done == 0){
		
		SDL_Delay(getRandomDelay());
		int randomBonusNumber = (rand()%(bonusSize));
		int index = 0;

		for(theIterator = bonusList->begin(); (theIterator != bonusList->end()) && (index < randomBonusNumber); theIterator++){
			index++;
		}
		
		Bonuz *theBonus = *theIterator;
		bool differentBonus = true;
		
		if (stage->getActiveBonus() != NULL){
			differentBonus = strcmp(stage->getActiveBonus()->getId().c_str(),theBonus->getId().c_str());
			
			if (differentBonus){
				Position * pClear = new Position();
				pClear->setPixel(stage->getActiveBonus()->getPosition()->getPixelX() - stage->getActiveBonus()->getRadius(),stage->getActiveBonus()->getPosition()->getPixelY() - stage->getActiveBonus()->getRadius());
				SketcherHelper::getInstance()->clearBackground(pClear,stage->getActiveBonus()->getRadius()*2,stage->getActiveBonus()->getRadius()*2);
				stage->setActiveBonus(NULL);
				delete pClear;
				SDL_Delay(15000);
			}
		}
		
		if (differentBonus){
			int randomHeight = (rand()%(stage->getResolution()->getHeight())+8);
			int randomWidth = (rand()%(stage->getResolution()->getWidth())+4);
			Position *position = new Position(randomWidth,randomHeight);
			
			if (stage->getActivatedBonus()!= NULL){
				stage->getActivatedBonus()->undoMagic(stage);
				SketcherHelper::getInstance()->clearLine(stage->getFrog()->getPosition(),stage->getLastMousePosition()) ;
				stage->setActivatedBonus(NULL);
			}
			
			theBonus->setPosition(position);
			stage->setActiveBonus(theBonus);
		}
		SketcherHelper::getInstance()->show();
	}
	return 0;
}

int getRandomDelay(){
	int random = (rand()%(maxDelayBonusTime)+ minDelayBonusTime);
	return random;
}